package com.yyq.sos.dao;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.persister.entity.SingleTableEntityPersister;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.yyq.adms.sysmanage.pojo.Accessory;
import com.yyq.adms.yyb.advance.pojo.STReport;
import com.yyq.adms.yyb.summary.pojo.TechnologyReport;
import com.yyq.adms.zz.pojo.Writings;
import com.yyq.sos.constants.Constants;
import com.yyq.sos.logs.LoggerProxy;
import com.yyq.sos.util.LogsUtil;
import com.yyq.sos.util.ObjectUtil;
import com.yyq.sos.util.SequencesUtil;
import com.yyq.sos.util.SysParametersUtil;


/**
 * 基本Dao接口实现类，此类封装了对数据的大部分的操作处理，如果需要对其进行
 * 扩展，则需要在其模块级别的子类中进行，不要在本类中做扩展处理
 * @author Administrator
 *
 */
public class BaseDaoImpl implements BaseDao
{

	/**
	 * 注入hibernateTemplate
	 */
	@Autowired
	private HibernateTemplate hibernateTemplate;
	
	/**
	 * 添加一个对象记录到数据库
	 * @param obj Object :需要保存的对象，映射一条记录
	 * @return long :返回生成的主键序列
	 */
	public Serializable add(Object obj) {
		Serializable[] ids = this.add(new Object[]{obj});
		Serializable id = null;
		if(ids!=null)
			id = ids[0];
		return id;
	}

	public Serializable buildPrimaryKey(Object obj){
		Serializable value = null;
		Class cls = obj.getClass();
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String name = meta.getIdentifierPropertyName();
		value = (Serializable)ObjectUtil.getValue(obj, ObjectUtil.getGetter(name), new Class[]{}, new Object[]{});
		if(value==null){
			Class type = ObjectUtil.getField(cls, name).getType();
			Long pkId = SequencesUtil.getInstance().getNextPk(cls);
			value = pkId;
			if(type.equals(Long.class)){
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{pkId});
			}else if(type.equals(Integer.class)){
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{new Integer(pkId.intValue())});
			}else{
				ObjectUtil.setValue(obj, ObjectUtil.getSetter(name), new Class[]{type}, new Object[]{new Short(pkId.shortValue())});
			}
		}
		return value;
	}
	

	/**
	 * 批量插入 
	 */
	public Serializable[] add(Object[] objs) {
		Serializable[] ids = null;
		String content = null;
		List list = new ArrayList();
		if(objs!=null && objs.length>0){
			Class cls = objs[0].getClass();
			ids = new Serializable[objs.length];
			try{
				for(int i=0,len=objs.length; i<len; ++i){
					ids[i] = this.buildPrimaryKey(objs[i]);
//System.out.println("ids------------------->"+ids[i]+"   cardTypeRelationid===>"+((CardTypeRelation)objs[i]).getRelId());
					list.add(objs[i]);
				}
				for(int i=0, len = objs.length; i<len; ++i) {
					ids[i] =  hibernateTemplate.save(objs[i]);
				}
				content = LogsUtil.getBatchSaveString(objs);
			}catch(Exception ex){
				ex.printStackTrace();
				content = this.getExceptionResult(ex);
				ids = null;
			}finally{
				LoggerProxy.getProxy().log(getTableName(cls),
						Constants.LOG_WRITE,ids!=null?"success":"fail",content);
			}
		}
		return ids;
	}
	
	@SuppressWarnings("unchecked")
	private boolean delete(Class cls,String hql){
		boolean bool =false; 
		String content = null;
		final String hqlStr = hql; 
		try{
			List list = (List)hibernateTemplate.execute(new HibernateCallback(){

				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					List list = session.createQuery(hqlStr.replaceAll("delete", "from ")).list();
					//session.createQuery(hqlStr).executeUpdate();
					return list;
				}
				
			});
			hibernateTemplate.deleteAll(list);
			deleteExtraInfo(list);
			bool = true;
			content = LogsUtil.getBatchDeleteString(list.toArray());
		}
		catch(Exception ex){
			content = this.getExceptionResult(ex);
		}
		finally{
			LoggerProxy.getProxy().log(null,
					Constants.LOG_DELETE,bool?"success":"fail",content,LoggerProxy.SAVE_TO_FILE);
			
			//LoggerProxy.getProxy().log(getTableName(cls),
				//	Constants.LOG_DELETE,bool?"success":"fail",content);
		}
		return bool;
	}
	
	/**
	 * 删除额外信息
	 * @param list
	 * @return
	 */
	private boolean deleteExtraInfo(List list){
		StringBuffer hql = new StringBuffer();
		boolean flag = false;
		String tableName = "";
		StringBuffer accessoryHql = new StringBuffer();
		for(int i=0;list != null && i<list.size();i++){
			Object obj = list.get(i);
			Long id = (Long)ObjectUtil.getValue(obj, "getId", null, null);
			if(i==0){
				Method m = ObjectUtil.getMethod(obj.getClass(), "getSentDep", null);
				tableName = this.getTableName(obj.getClass());
				if(m != null || obj.getClass()==Writings.class 
						|| obj.getClass() == STReport.class 
						|| obj.getClass()==TechnologyReport.class){
					flag = true;
					hql.append("delete from RecordSentDep where (sourceRecordId=")
					   .append(id).append(" and yyqTableName='").append(tableName)
					   .append("') ");
				}
				accessoryHql.append("from Accessory where (sourceRecordId=").append(id)
				            .append(" and yyqTableName='").append(tableName).append("') ");
				
			}else{
				if(flag)
					hql.append(" or (sourceRecordId=").append(id).append(" and yyqTableName='")
				   .append(tableName).append("') ");
				accessoryHql.append(" or (sourceRecordId=").append(id)
	            	        .append(" and yyqTableName='").append(tableName).append("') ");
			}
		}
		
		if(!hql.toString().equals("")){
			hibernateTemplate.bulkUpdate(hql.toString());
			//this.delete(hql.toString());
		}
		List data = this.search(accessoryHql.toString());
		if(data != null && data.size()>0){
			String accessorPath = SysParametersUtil.getInstance().getValue("ACCESSORY_PATH");
			for(int i=0;i<data.size();i++){
				Accessory accessory = (Accessory)data.get(i);
				File file = new File(accessorPath+File.separator+accessory.getAttachmentName());
				if(file.exists()){
					file.delete();
				}
			}
			hibernateTemplate.bulkUpdate(accessoryHql.toString().replaceAll("from", "delete"));
			String content = LogsUtil.getBatchDeleteString(data.toArray());
			LoggerProxy.getProxy().log(null,
					Constants.LOG_DELETE,"success",content,LoggerProxy.SAVE_TO_FILE);
			
		}
		return true;
	}
	
	/**
	 * 删除一条记录
	 */
	public boolean delete(Object obj){
		String hql = this.getDeleteHql(obj, null,null);
		return this.delete(obj.getClass(), hql);
		
	}
	
	private String getDeleteHql(Object obj,Class cls,java.io.Serializable[] ids){
		if(obj!=null)
			cls = obj.getClass();
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String name = meta.getIdentifierPropertyName();
		if(ids == null){
			ids = new java.io.Serializable[1];
			ids[0] = (Serializable)ObjectUtil.getValue(obj, ObjectUtil.getGetter(name), new Class[]{}, new Object[]{});
		}
		Class type = ObjectUtil.getField(cls, name).getType();
		StringBuffer buf = new StringBuffer("delete "+cls.getName()+" where ");
		for(int i=0,len = ids.length; i<len; ++i){
			if(i!=0)
				buf.append(" or ");
			if(type.equals(String.class)){
				buf.append(name);
				buf.append("='");
				buf.append(ids[i]);
				buf.append("'");
			}
			else{
				buf.append(name);
				buf.append("=");
				buf.append(ids[i]);
			}
		}
		return buf.toString();
	}
	
	
	/**
	 * 删除一条记录
	 */
	public boolean delete(Class cls, long id){
		return this.delete(cls, this.getDeleteHql(null, cls, new java.io.Serializable[]{new Long(id)}));
	}
	
	/**
	 * 删除一条记录
	 */
	public boolean delete(Class cls, Serializable id){
		return this.delete(cls, this.getDeleteHql(null, cls, new Serializable[]{id}));
	}
	
	/**
	 * 删除多条记录
	 */
	public boolean delete(Class cls, long[] ids){
		java.io.Serializable[] id = new Serializable[ids.length];
		for(int i=0, len=ids.length; i<len; ++i)
			id[i] = new Long(ids[i]);
		return this.delete(cls, this.getDeleteHql(null, cls, id));
	}
	
	/**
	 * 删除多条记录
	 */
	public boolean delete(Class cls, Serializable[] ids)
	{
		return this.delete(cls, this.getDeleteHql(null, cls, ids));
	}
	
	private String getExceptionResult(Exception ex){
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ex.printStackTrace(new PrintStream(baos));
		System.out.println("-------------------------   Dao操作出现异常        ------------->");
		return baos.toString();
	}
	
	/**
	 * 根据sql删除记录
	 */
	public boolean delete(String sql)
	{
		boolean bool =false;
		List list = null;
		String content = "";
		try{
			final String sqlStr = sql;
			list = hibernateTemplate.execute(new HibernateCallback<List>(){

				public List doInHibernate(Session session)
						throws HibernateException, SQLException {
					String regex="";
					if(sqlStr.toLowerCase().indexOf("from")<0)
						regex=" from ";
					String hql = sqlStr.replaceAll("delete", regex);
					List list = session.createQuery(hql).list();
					session.createQuery(sqlStr).executeUpdate();
					return list;
				}
				
			});
			if(list.size()>0)
			hibernateTemplate.deleteAll(list);
			bool = true;
			content = LogsUtil.getBatchDeleteString(list.toArray());
		}catch(Exception ex){
			bool = false;
			content = getExceptionResult(ex);
		}finally{
			if(list!=null && list.size()>0){
				LoggerProxy.getProxy().log(null,
						Constants.LOG_DELETE,bool?"success":"fail",content,LoggerProxy.SAVE_TO_FILE);
				
				/*
				  Class cls = list.get(0).getClass();
				  LoggerProxy.getProxy().log(getTableName(cls),
						Constants.LOG_DELETE,bool?"success":"fail",content);*/
			}
		}
		return bool;
	}

	
	/**
	 * 根据主键查找一条记录
	 */
	public Object findByPk(Class cls, Serializable id)
	{
		Object obj = null;
		try{
			obj = hibernateTemplate.get(cls.getName(), id);			
		}finally{
		}
		return obj;
	}
	
	/**
	 * 根据主键查找一条记录
	 */
	public Object findByPk(Class cls, long id)
	{
		Object obj = null;
		try{
			obj = hibernateTemplate.get(cls.getName(), Long.valueOf(id));
		}finally{
		}
		return obj;
	}
	
	/**
	 * 根据sql查找一条记录
	 */
	public Object findByPk(String sql)
	{
		Object obj = null;
		try{
			List list = hibernateTemplate.find(sql);
			if(list!=null && list.size()!=0)
				obj = list.get(0);
		}finally{
		}
		return obj;
	}

	/**
	 * 查询全部记录
	 */
	public List list(Class cls)
	{
		List list = null;
		final Class temp=cls;
		try{
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					return session.createCriteria(temp).list();
				}
				
			});
			
		}finally{
		}
		return list;
	}
	
	/**
	 * 查询全部记录
	 */
	public List list(String sql)
	{
		List list = null;
		Session session = null;
		final String temp = sql;
		try{
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					return session.createQuery(temp).list();
				}
				
			});
		}finally{
		}
		return list;
	}

	/**
	 * 查询某页记录
	 * @param page 每页记录数
	 * @param size 当前页码
	 */
	public List listPage(Class cls, int page, int size)
	{
		List list = null;
		try{
			final String sql = this.getQueryHql(cls);
			final int pageTmp = page;
			final int sizeTmp = size;
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query query = session.createQuery(sql);
					query.setFirstResult((pageTmp-1)*sizeTmp);
					query.setMaxResults(sizeTmp);
					List list = query.list();
					return list;
				}
				
			});
			
		}finally{
		}
		return list;
	}
	
	private String getQueryHql(Class cls){
		ClassMetadata meta = this.getSessionFactory().getClassMetadata(cls);
		String[] fields = meta.getPropertyNames();
		String sql="from "+cls.getName();
		boolean bool = false;
		for(int i=0; i<fields.length; ++i){
			if(fields[i].toUpperCase().equals("STS")){
				bool = true;
				sql += " order by sts asc";
			}
		}
		for(int i=0; i<fields.length; ++i){
			if(fields[i].toUpperCase().equals("STSDATE")){
				if(bool)
					sql += ",stsDate desc ";
				else
					sql += " order by stsDate desc ";
			}
			if(fields[i].toUpperCase().equals("STSTIME")){
				if(bool)
					sql += ",stsTime desc ";
				else
					sql += " order by stsTime desc ";
			}
		}
		return sql;
	}
	
	/**
	 * 查询某页记录
	 * @param page 每页记录数
	 * @param size 当前页码
	 */
	public List listPage(String sql, int page, int size)
	{
		List list = null;
		try{
			final String sqlTmp = sql;
			final int pageTmp = page;
			final int sizeTmp = size;
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query query = session.createQuery(sqlTmp);
					query.setFirstResult((pageTmp-1)*sizeTmp);
					query.setMaxResults(sizeTmp);
					List list = query.list();
					return list;
				}
				
			});
		}finally{
		}
		return list;
	}
	
	/**
	 * 综合查询方法
	 */
	public List search(String sql)
	{
		List list = null;
		try{
			list = hibernateTemplate.find(sql);
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return list;
	}
	
	/**
	 * 综合查询方法，带有分页功能
	 */
	public List search(String sql,int page,int size)
	{
		List list = null;
		try{
			final String sqlTmp = sql;
			final int pageTmp = page;
			final int sizeTmp = size;
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					Query query = session.createQuery(sqlTmp);
					query.setFirstResult((pageTmp-1)*sizeTmp);
					query.setMaxResults(sizeTmp);
					List list = query.list();
					return list;
				}
				
			});
			
		}finally{
		}
		return list;
	}
	
	/*
	 * 修改一条记录
	 */
	public boolean update(Object obj)
	{
		boolean bool = false;
		String content = null;
		Object beforeVo = null;
		Object vo = null;
		try{
			Class cls = obj.getClass();
			ClassMetadata cmd = getSessionFactory().getClassMetadata(cls);
			String pkId = cmd.getIdentifierPropertyName();
			Serializable id = cmd.getIdentifier(obj, EntityMode.POJO);
			vo = hibernateTemplate.get(obj.getClass(), id);
			beforeVo = ObjectUtil.cloneObject(vo);//this.processUpdateObject(vo);
			
			Method[] method = obj.getClass().getDeclaredMethods();
			for(int i=0;i<method.length; ++i){
				Method m = method[i];
				if(m.getName().startsWith("get")){
					Object value = m.invoke(obj, null);
					if(value!=null){
						try{
							Method voM = null;
							if(value.getClass().getName().indexOf("Timestamp")>0 || value.getClass().getName().indexOf("Time")>0 ||value.getClass().getName().indexOf("Date")>0)
								voM = vo.getClass().getMethod("set"+m.getName().substring(3), new Class[]{Date.class});
							else
								voM = vo.getClass().getMethod("set"+m.getName().substring(3), new Class[]{value.getClass()});
							voM.invoke(vo, new Object[]{value});
						}catch(Exception e){
							e.printStackTrace();
						}
					}
				}
			}
			hibernateTemplate.update(vo);
			bool = true;
			content = LogsUtil.getUpdateString(beforeVo, vo);
		}catch(Exception ex){
			content = this.getExceptionResult(ex);
		}finally{
			LoggerProxy.getProxy().log(getTableName(obj.getClass()),
						Constants.LOG_UPDATE,bool?"success":"fail",content);
		}
		return bool;
	}
	
	/**
	 * 修改一条记录，根据sql
	 */
	@SuppressWarnings("unchecked")
	public boolean update(String sql)
	{
		boolean bool = false;
		try
		{
			final String sqlTmp = sql;
			hibernateTemplate.execute(new HibernateCallback(){

				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					session.createQuery(sqlTmp).executeUpdate();
					return null;
				}
				
			});
		}
		catch (Exception e){
			e.printStackTrace();
		}finally{
		}
		return bool;
	}
	
	
	/**
	 * 批量更新
	 */
	public boolean update(Object[] objs)
	{
		boolean bool = false;
		try{
			for(int i=0; i<objs.length; ++i)
			{
				hibernateTemplate.update(objs[i]);
			}
			bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
		}
		finally{
		}
		return bool;
	}
	
	/**
	 * 查询记录数
	 */
	public long count(Class cls)
	{
		long count = 0;
		try{
			final Class clsTmp = cls;
			count = (Long) hibernateTemplate.execute(new HibernateCallback() {
				public Object doInHibernate(Session s) throws HibernateException,
						SQLException {
					Query query = s.createQuery("select count(*) from "+clsTmp.getName());
					System.out.println(query);
					Long c = (Long)query.uniqueResult();
					
					System.out.println(c);
					return c;
				}
			});
		}finally{
		}
		return count;
	}
	
	/**
	 * 查询记录数
	 */
	public long count(String sql)
	{
		long count = 0;
		Session session = null;
		try{
			int index = sql.toLowerCase().indexOf("from ");
			if(index>-1)
			{
				sql = sql.substring(index);
			}
			//修正查询记录数记录数时去掉order by 子句
			if (sql.toLowerCase().matches(".*order\\s+by.*")) {
				index=-1;
		    	index = sql.toLowerCase().indexOf("order");
		    	if (index >1) {
		    		sql = sql.substring(0, index);
		    	}
			}
			/*index = sql.toLowerCase().indexOf("order by");
			if(index>1)
			{
				sql = sql.substring(0, index);
			}*/
			final String sqlTmp = sql;
			count = (Long) hibernateTemplate.execute(new HibernateCallback() {
				public Object doInHibernate(Session s) throws HibernateException,
						SQLException {
					return s.createQuery("select count(*) "+sqlTmp).uniqueResult();
				}
			});
		}finally{
		}
		return count;
	}
	
	/**
	 * 根据sql判断某条记录是否存在
	 */
	public boolean exist(String sql)
	{
		boolean bool = false;
		try{
			if(hibernateTemplate.find(sql).size()>0)
				bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return bool;
	}
	
	/**
	 * 根据ID判断某条记录是否存在
	 */
	public boolean exist(Class cls,java.io.Serializable id)
	{
		boolean bool = false;
		try{
			Object obj = hibernateTemplate.get(cls, id); 
			if(obj != null)
				bool = true;
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return bool;
	}
	
	/**
	 * 取得某个字段的最大值
	 */
	public Object max(Class cls, String fieldName,String where) {
		Object value = null;
		Session session = null;
		try{
			String sql = "select max("+fieldName+") from "+cls.getName();
			if(where!=null && !where.trim().equals(""))
				sql += " where "+where;
			List list = hibernateTemplate.find(sql);
			if(list!=null && list.size()>0)
				value = list.get(0);
		}catch(Exception ex){
			ex.printStackTrace();
		}finally{
		}
		return value;
	}
	
	/**
	 * 修改一条记录，根据 sql
	 */
	public boolean execSql(String sql)
	{
		Transaction tx =null;
		boolean bool = false;
		Session session = null;
		try
		{
			
			session = this.getSessionFactory().openSession();
			tx = session.beginTransaction();
			Connection conn = session.connection();
			conn.prepareStatement(sql).executeUpdate();
			tx.commit();
			conn.close();
			bool = true;
		}
		catch (SQLException e)
		{
			e.printStackTrace();
			tx.rollback();
		}finally{
			if(session !=null){
				session.close();
			}
		}
		return bool;
	}

	public List listSql(String sql, int page, int size) {
		List list =null;
		try
		{
			final String sqlTmp = sql;
			final int pageTmp = page;
			final int sizeTmp = size;
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					SQLQuery query = session.createSQLQuery(sqlTmp);
					query.setFirstResult((pageTmp-1)*sizeTmp);
					query.setMaxResults(sizeTmp);
					return query.list();
				}});
		}
		catch (Exception e){
			e.printStackTrace();
		}finally{
		}
		return list;
	}

	public List listSql(String sql) {
		List list =null;
		try
		{
			final String sqlTmp = sql;
			list = hibernateTemplate.executeFind(new HibernateCallback(){
				public Object doInHibernate(Session session)
						throws HibernateException, SQLException {
					SQLQuery query = session.createSQLQuery(sqlTmp);
					return query.list();
				}});
			
		}
		catch (Exception e){
			e.printStackTrace();
		}finally{
		}
		return list;
	}
	
	/**
	 * 验证有效期
	 * @param effDate
	 * @param expDate
	 * @return
	 */
	public boolean validDateAvai(Class cls,String valueCondition,String effDate,String expDate){
		boolean bool = true;
		String sql = "from "+cls.getName()+" obj where ((obj.effDate <= '"+effDate+"' and obj.expDate>='"+effDate+"') or " +
				"(obj.effDate <= '"+expDate+"' and obj.expDate>='"+expDate+"')) and "+valueCondition;
		try{
			List list = hibernateTemplate.find(sql);
			if(list!=null && list.size()>0)
				bool = false;
		}
		catch (Exception e){
			bool = false;
			e.printStackTrace();
		}finally{
		}
		return bool;
	}

	public HibernateTemplate getHibernateTemplate() {
		return hibernateTemplate;
	}

	public String getTableName(Class cls){
		SingleTableEntityPersister entityPersister=(SingleTableEntityPersister)this.getSessionFactory().getClassMetadata(cls);
		return entityPersister.getTableName();
	}
	public SessionFactory getSessionFactory() {
		return hibernateTemplate.getSessionFactory();
	}

	public boolean logicDelete(Serializable[] ids) {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean execHql(String sql) {
		try {
			hibernateTemplate.bulkUpdate(sql);
			return true;
		} catch (DataAccessException e) {
			e.printStackTrace();
			return false;
		}
	}
}
